package com.heima.account.handler;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.heima.commons.enums.BusinessErrors;
import com.heima.commons.exception.BusinessRuntimeException;
import com.heima.modules.po.VehiclePO;
import okhttp3.*;
import org.apache.commons.io.FileUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;

@Component
public class AiHelper {
    @Value("${baidu.apikey}")
    private String API_KEY;
    @Value("${baidu.secretkey}")
    private String SECRET_KEY;

    private static final String TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token";
    private static final String VEHICLE_LICENSE_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_license";
    private static final String LICENSE_PLATE_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate";

    private final static Logger logger = LoggerFactory.getLogger(AiHelper.class);

    final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();

    /**
     * 获取文件base64编码
     *
     * @param path      文件路径
     * @param urlEncode 如果Content-Type是application/x-www-form-urlencoded时,传true
     * @return base64编码信息，不带文件头
     * @throws IOException IO异常
     */
    private String getFileContentAsBase64(String path, boolean urlEncode) throws IOException {
        // 检查文件是否存在
        File file = new File(path);
        if (!file.exists()) {
            throw new IOException("文件不存在: " + path);
        }
        if (!file.isFile()) {
            throw new IOException("路径不是有效文件: " + path);
        }

        byte[] b = Files.readAllBytes(Paths.get(path));
        String base64 = Base64.getEncoder().encodeToString(b);
        if (urlEncode) {
            base64 = URLEncoder.encode(base64, "utf-8");
        }
        return base64;
    }

    /**
     * 从URL下载文件到临时目录
     *
     * @param url URL地址
     * @return 临时文件路径
     * @throws IOException IO异常
     */
    private String downloadFileFromUrl(String url) throws IOException {
        // 创建临时目录
        File tempDir = new File(System.getProperty("java.io.tmpdir"), "vehicle_auth");
        if (!tempDir.exists()) {
            tempDir.mkdirs();
        }

        // 生成临时文件名
        String fileName = "temp_" + System.currentTimeMillis() + ".jpg";
        File tempFile = new File(tempDir, fileName);

        // 下载文件
        Request request = new Request.Builder().url(url).build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("下载文件失败: " + response);
            }
            if (response.body() == null) {
                throw new IOException("下载文件为空");
            }
            FileUtils.writeByteArrayToFile(tempFile, response.body().bytes());
        }

        return tempFile.getAbsolutePath();
    }

    /**
     * 识别行驶证信息
     *
     * @param imageBase64 行驶证图片base64编码
     * @return 识别结果
     * @throws IOException IO异常
     */
    public String recognizeVehicleLicense(String imageBase64) throws IOException {//需要你传入一个参数：imageBase64
        // 获取access_token
        String accessToken = getAccessToken();

        // 构造请求参数
        String param = "image=" + imageBase64;

        // 发送请求
        Request request = new Request.Builder()
                .url(VEHICLE_LICENSE_URL + "?access_token=" + accessToken)
                .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), param))
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();

        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("行驶证识别请求失败: " + response);
            }
            if (response.body() == null) {
                throw new IOException("行驶证识别响应为空");
            }
            return response.body().string();
        }
    }

    /**
     * 识别车牌信息
     *
     * @param imageBase64 车牌图片base64编码
     * @return 识别结果
     * @throws IOException IO异常
     */
    public String recognizeLicensePlate(String imageBase64) throws IOException {
        // 获取access_token
        String accessToken = getAccessToken();

        // 构造请求参数
        String param = "image=" + imageBase64;

        // 发送请求
        Request request = new Request.Builder()
                .url(LICENSE_PLATE_URL + "?access_token=" + accessToken)
                .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), param))
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();

        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("车牌识别请求失败: " + response);
            }
            if (response.body() == null) {
                throw new IOException("车牌识别响应为空");
            }
            return response.body().string();
        }
    }

    /**
     * 获取百度AI access_token
     *
     * @return access_token
     * @throws IOException IO异常
     */
    private String getAccessToken() throws IOException {
        String accessTokenUrl = TOKEN_URL + "?grant_type=client_credentials"
                + "&client_id=" + API_KEY
                + "&client_secret=" + SECRET_KEY;

        Request request = new Request.Builder()
                .url(accessTokenUrl)
                .get()
                .build();

        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("获取access_token失败: " + response);
            }
            if (response.body() == null) {
                throw new IOException("获取access_token响应为空");
            }
            String result = response.body().string();
            JSONObject jsonObject = new JSONObject(result);
            return jsonObject.getString("access_token");
        }
    }

    public static void main(String[] args) throws IOException {
        String code = new AiHelper().getLicense(null);
        System.out.println(code);
    }

    /*
    图像识别，获取车牌信息
    文档（行驶证识别）：https://cloud.baidu.com/doc/OCR/s/yk3h7y3ks
    文档（车牌识别）：https://cloud.baidu.com/doc/OCR/s/ck3h7y191
    获取车辆照片url
    将url下载到某个临时文件夹
    将文件编码为base64
    调百度AI接口，返回对应信息
    对比：行驶证车牌 和 车辆车牌是否一致
    如果一致，设置车牌信息，认证通过，身份变更为车主

    简化版业务流程（至少完成）：识别车辆车牌号即可
    */
    public String getLicense(VehiclePO vehiclePO) throws IOException {
        //TODO 2.1.1百度AI识别
        if (vehiclePO == null) {
            throw new IllegalArgumentException("车辆信息不能为空");
        }

        // 获取车辆照片和行驶证照片URL
        String carFrontPhotoUrl = vehiclePO.getCarFrontPhoto();
        String carBackPhotoUrl = vehiclePO.getCarBackPhoto();

        if (carFrontPhotoUrl == null || carFrontPhotoUrl.isEmpty()) {
            throw new IllegalArgumentException("车辆照片URL不能为空");
        }

        if (carBackPhotoUrl == null || carBackPhotoUrl.isEmpty()) {
            throw new IllegalArgumentException("行驶证照片URL不能为空");
        }

        // 下载车辆照片和行驶证照片到临时文件
        String carFrontPhotoPath = downloadFileFromUrl(carFrontPhotoUrl);
        String carBackPhotoPath = downloadFileFromUrl(carBackPhotoUrl);

        try {
            // 识别车牌照片中的车牌号
            String carFrontPhotoBase64 = getFileContentAsBase64(carFrontPhotoPath, true);
            String licensePlateResult = recognizeLicensePlate(carFrontPhotoBase64);
            JSONObject licensePlateJson = new JSONObject(licensePlateResult);//用JSONObject工具把识别结果字符串转换成 JSON 对象（可以理解为一个带键值对的 “字典”，方便按名称提取内容）//比如 JSON 里可能有"words_result": { "number": "京A12345" }这样的结构

            // 检查车牌识别是否成功
            if (!licensePlateJson.has("words_result")) {
                throw new IOException("车牌识别失败，无法解析识别结果");
            }

            JSONObject licensePlateWordsResult = licensePlateJson.getJSONObject("words_result");
            if (!licensePlateWordsResult.has("number")) {
                throw new IOException("车牌识别失败，未找到车牌号码");
            }

            String licensePlateNumber = licensePlateWordsResult.getString("number");//从之前获取的车牌识别结果（licensePlateWordsResult这个 JSON 对象）中，提取"number"对应的值

            // 识别行驶证照片中的车牌号
            String carBackPhotoBase64 = getFileContentAsBase64(carBackPhotoPath, true);//调用getFileContentAsBase64方法，把行驶证照片（路径是carBackPhotoPath）转换成 base64 编码字符串//第二个参数true表示需要 URL 编码，方便网络传输
            String vehicleLicenseResult = recognizeVehicleLicense(carBackPhotoBase64);//把行驶证照片的 base64 字符串传给recognizeVehicleLicense方法（之前讲过的行驶证识别方法）
            JSONObject vehicleLicenseJson = new JSONObject(vehicleLicenseResult);//用JSONObject工具把行驶证识别结果字符串转换成 JSON 对象，方便提取信息

            // 检查行驶证识别是否成功
            if (!vehicleLicenseJson.has("words_result")) {
                throw new IOException("行驶证识别失败，无法解析识别结果");
            }

            JSONObject vehicleLicenseWordsResult = vehicleLicenseJson.getJSONObject("words_result");//从行驶证 JSON 对象中，取出"words_result"对应的值（这也是一个 JSON 对象），保存到vehicleLicenseWordsResult里//比如 JSON 里可能有"words_result": { "号牌号码": { "words": "京A12345" } }这样的结构·
            if (!vehicleLicenseWordsResult.has("号牌号码")) {
                throw new IOException("行驶证识别失败，未找到号牌号码字段");
            }

            JSONObject plateNumberObj = vehicleLicenseWordsResult.getJSONObject("号牌号码");
            if (!plateNumberObj.has("words")) {
                throw new IOException("行驶证识别失败，号牌号码字段格式错误");
            }

            String vehicleLicensePlateNumber = plateNumberObj.getString("words");

            // 比较两个车牌号是否一致
            if (licensePlateNumber.equals(vehicleLicensePlateNumber)) {
                logger.info("车辆认证成功，车牌号码: {}", licensePlateNumber);
                return licensePlateNumber;
            } else {
                logger.warn("车辆认证失败，车牌照片中的车牌号: {} 与行驶证中的车牌号: {} 不一致",
                        licensePlateNumber, vehicleLicensePlateNumber);
                throw new IOException("车辆认证失败，车牌照片与行驶证中的车牌号不一致");
            }
        } finally {
            // 清理临时文件
            try {
                new File(carFrontPhotoPath).delete();
                new File(carBackPhotoPath).delete();
            } catch (Exception e) {
                logger.warn("清理临时文件失败", e);
            }
        }
    }
}
